# coding=utf-8

from copy import deepcopy

from app.models import Case, Dispatcher
from app.cores.logger import DispatcherLogger
from app.cores.dictionaries import DISPATCHER_TYPE, REPORT_RESULT
from app.cores.dispatcher import AbstractCaseDispatcher
from app.cores.case.http.request_util import handle_url, handle_headers
from app.cores.case.http.http_cookie_pool_manager import HTTPCookiePoolManager
from app.cores.case.http.http_header_pool_manager import HTTPHeaderPoolManager
from app.cores.case.base.script import exec_postprocessor_script, exec_preprocessor_script
from app.cores.case.base.last_result import LastResult
from app.cores.case.base.expectation import get_expectations_result
from app.cores.case.http.request import make_request


class HTTPCaseDispatcher(AbstractCaseDispatcher):
    def __init__(self, case, dispatcher_type=DISPATCHER_TYPE.DEBUG, logger=None, dispatcher=None):
        """
        :param case: 单个HTTPCase案例请求数据
        :type case: Case
        :param dispatcher_type: 标识构建是通过单独案例调试(DISPATCHER_TYPE.DEBUG)还是通过模块/项目构建测试(DISPATCHER_TYPE.BUILD)
        :type dispatcher_type: str
        :param logger: 当dispatcher_type为DISPATCHER_TYPE.BUILD时，需要传入调度日志
        :type logger: DispatcherLogger
        :param dispatcher: 当dispatcher_type为DISPATCHER_TYPE.BUILD时，需要传入调度数据
        :type dispatcher: Dispatcher
        """
        super().__init__(case=case, dispatcher_type=dispatcher_type, logger=logger, dispatcher=dispatcher)

        # 请求对象
        self.request_ = None

        # 后处理脚本断言结果
        self.postprocessor_failure = None
        # 后处理脚本错误信息
        self.postprocessor_failure_message = None

        # 组件期望断言结果
        self.expectations_result = False

        # cookie数据
        self.rcj = None

        # http请求字段
        self.protocol = None
        self.domain = None
        self.port = None
        self.method = None
        self.path = None
        self.encoding = None
        self.expectation_logic = None
        self.message_body = None
        self.content_type = None
        self.postprocessor = None
        self.parameters = None
        self.expectations = None
        self.file_upload = None
        self.headers = None

    def set_up(self):
        super().set_up()
        # 获取cookie
        self.rcj = HTTPCookiePoolManager.get_request_cookie_jar(type=self.dispatcher_type)
        # 获取HTTP请求头
        self.headers = HTTPHeaderPoolManager.get_http_header(project_id=self.case.scene.module.project.id)
        self.headers = deepcopy(self.headers)  # 后面会对请求头数据更新，但不要影响HTTPHeaderPool中的数据

        # 预处理脚本执行
        preprocessor_script = self.case.specific_case.preprocessor_script_
        exec_preprocessor_script(
            source=preprocessor_script,
            project_id=self.case.scene.module.project_id,
            log=self.dispatcher_logger.logger,
        )

    def _load_data(self):  # 在execute执行开始时执行
        super()._load_data()
        self.protocol = self.case.specific_case.protocol
        self.domain = self.case.specific_case.domain_
        self.port = self.case.specific_case.port_
        self.method = self.case.specific_case.method
        self.path = self.case.specific_case.path_
        self.encoding = self.case.specific_case.encoding_
        self.expectation_logic = self.case.specific_case.expectation_logic
        self.message_body = self.case.specific_case.message_body_
        self.content_type = self.case.specific_case.content_type
        self.postprocessor_script = self.case.specific_case.postprocessor_script_
        self.parameters = self.case.specific_case.parameters
        self.expectations = self.case.specific_case.expectations
        self.file_upload = self.case.specific_case.file_upload
        _headers = self.case.specific_case.headers
        self.headers.update(handle_headers(_headers))  # 将HTTPCase中定义的headers覆盖到HTTPHeaderManagerTool中

    def execute(self):
        super().execute()
        # 请求发送
        url = handle_url(protocol=self.protocol,
                         domain=self.domain,
                         port=self.port,
                         path=self.path)
        self.request_ = make_request(method=self.method,
                                     url=url,
                                     parameters=self.parameters,
                                     message_body=self.message_body,
                                     cookies=self.rcj,
                                     file_upload=self.file_upload,
                                     content_type=self.content_type,
                                     headers=self.headers)
        self.request_.send()

    def tear_down(self):
        super().tear_down()
        # 更新结果数据1
        LastResult.update_request_and_response_to_last_result(
            request_headers=self.request_.request_headers,
            request_body=self.request_.request_body,
            response_headers=self.request_.response_headers,
            response_body=self.request_.response_body,
        )
        # 后处理脚本执行
        self.postprocessor_failure, self.postprocessor_failure_message = exec_postprocessor_script(
            source=self.postprocessor_script,
            project_id=self.case.scene.module.project_id,
            case=self.case,
            log=self.dispatcher_logger.logger,
        )
        # 进行期望判断
        self.expectations_result = get_expectations_result(expectations=self.expectations,
                                                           request=self.request_,
                                                           expectation_logic=self.expectation_logic)
        # 更新结果数据2
        LastResult.update_result_to_last_result(result=self.expectations_result)
        # cookie处理
        HTTPCookiePoolManager.update_cookie_pool(
            rcj=self.request_.response.cookies,
            type=self.dispatcher_type,
        )

    def run(self):
        super().run()
        log_text = self.dispatcher_logger.get_string_buffer()
        # return self.request_, self.expectations_result, self.expectations, self.postprocessor_failure, log_text
        return dict(
            request_=self.request_,
            expectations_result=self.expectations_result,
            expectations=self.expectations,
            postprocessor_failure=self.postprocessor_failure,
            postprocessor_failure_message=self.postprocessor_failure_message,
            log_text=log_text,
            result=self.get_assert_result(),
            elapsed_time=self.request_.elapsed_time,
        )

    def get_assert_result(self):
        """
        案例执行的断言结果
        :return: REPORT_RESULT
        """
        if self.expectations:
            result = all([self.expectations_result, not self.postprocessor_failure])
        else:
            result = not self.postprocessor_failure
        if result:
            return REPORT_RESULT.SUCCESS
        else:
            return REPORT_RESULT.FAILURE
